/**
 * Copyright (c) 2018 开源 All rights reserved.
 * <p>
 * https://www.chengcang.com
 * <p>
 * 版权所有，侵权必究！
 */

package com.chengcang.admin.modules.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chengcang.admin.modules.security.user.SecurityUser;
import com.chengcang.admin.modules.security.user.UserDetail;
import com.chengcang.admin.modules.sys.dao.SysDeptDao;
import com.chengcang.admin.modules.sys.dao.SysUserDao;
import com.chengcang.admin.modules.sys.dto.SysDeptDTO;
import com.chengcang.admin.modules.sys.dto.SysDeptUserDto;
import com.chengcang.admin.modules.sys.entity.SysDeptEntity;
import com.chengcang.admin.modules.sys.entity.SysUserEntity;
import com.chengcang.admin.modules.sys.service.SysDeptService;
import com.chengcang.common.constant.Constant;
import com.chengcang.common.enums.SuperAdminEnum;
import com.chengcang.common.exception.CustomException;
import com.chengcang.common.exception.ErrorCode;
import com.chengcang.common.page.PageData;
import com.chengcang.common.service.impl.CrudServiceImpl;
import com.chengcang.common.utils.ConvertUtils;
import com.chengcang.common.utils.TreeUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;


@Service
public class SysDeptServiceImpl extends CrudServiceImpl<SysDeptDao, SysDeptEntity, SysDeptDTO> implements SysDeptService {
    @Autowired
    private SysUserDao sysUserDao;


    @Override
    public QueryWrapper<SysDeptEntity> getWrapper(Map<String, Object> params) {
        String id = (String) params.get("id");

        QueryWrapper<SysDeptEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(id), "id", id);
        wrapper.eq(SecurityUser.getTenantId() != null, "tenant_id", SecurityUser.getTenantId());
        wrapper.like(params.get("name") != null, "name", params.get("name"));

        return wrapper;
    }

    @Override
    public PageData<SysDeptDTO> page(Map<String, Object> params) {
        IPage<SysDeptEntity> ipage = getPage(params, Constant.CREATE_DATE, false);
        List<SysDeptEntity> sysDeptEntities = baseDao.selectList(getWrapper(params));
        if (CollectionUtils.isNotEmpty(sysDeptEntities)) {

            // 统计成员数量
//            List<Long> deptIds = sysDeptEntities.stream().map(SysDeptEntity::getId).collect(toList());
//            List<Map<Long, Long>> countByDeptIds = sysUserDao.getCountByDeptIds(deptIds);



            for (SysDeptEntity sysDeptEntity : sysDeptEntities) {
                String pids = sysDeptEntity.getPids();
                if (StringUtils.isBlank(pids) || Objects.equals(pids, "0")) {
                    sysDeptEntity.setAllName(sysDeptEntity.getName());
                } else {
                    String[] ids = pids.split(",");
                    List<SysDeptEntity> deptEntities = baseDao.selectBatchIds(Arrays.asList(ids));
                    if (CollectionUtils.isNotEmpty(deptEntities)) {
                        sysDeptEntity.setAllName(deptEntities.stream().map(SysDeptEntity::getName).collect(Collectors.joining("-")) + "-" + sysDeptEntity.getName());
                    }
                }
                Optional.ofNullable(sysDeptEntity.getExecutiveId()).ifPresent(o -> {
                    SysUserEntity sysUserEntity = sysUserDao.selectById(sysDeptEntity.getExecutiveId());
                    if (sysUserEntity != null) {
                        sysDeptEntity.setExecutive(sysUserEntity.getRealName());
                    }
                });
                sysDeptEntity.setMemberCount(sysUserDao.selectCount(new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getDeptId, sysDeptEntity.getId()).eq(SysUserEntity::getDeleted, 0)));
            }
        }
        PageData<SysDeptDTO> page = getPageData(sysDeptEntities, ipage.getTotal(), SysDeptDTO.class);
        return page;
    }

    @Override
    public List<SysDeptDTO> list(Map<String, Object> params) {
        //普通管理员，只能查询所属部门及子部门的数据
        UserDetail user = SecurityUser.getUser();
        if (SecurityUser.getUserType() == SuperAdminEnum.NO.value()) {
            params.put("deptIdList", getSubDeptIdList(user.getDeptId()));
        }
        params.put("tenantId", SecurityUser.getTenantId());
        //查询部门列表
        List<SysDeptEntity> entityList = baseDao.getList(params);

        List<SysDeptDTO> dtoList = ConvertUtils.sourceToTarget(entityList, SysDeptDTO.class);
        List<SysDeptDTO> build = TreeUtils.build(dtoList);
        for (SysDeptDTO deptDTO : build) {
            List<SysDeptUserDto> sysDeptUserDtos = new ArrayList<>();

            getUserByDeptId(sysDeptUserDtos, deptDTO);
            deptDTO.setUserList(sysDeptUserDtos);
        }
        return build;
    }

    private void getUserByDeptId(List<SysDeptUserDto> sysDeptUserDtos, SysDeptDTO deptDTO) {
        List<SysUserEntity> sysUserEntities = sysUserDao.selectList(new LambdaQueryWrapper<SysUserEntity>()
                .eq(SysUserEntity::getDeptId, deptDTO.getId()).select(SysUserEntity::getId, SysUserEntity::getRealName));
        sysDeptUserDtos.addAll(sysUserEntities.stream().map(o -> new SysDeptUserDto(o.getId(), o.getRealName())).collect(toList()));
        for (Object child : deptDTO.getChildren()) {
            SysDeptDTO sysUserEntity = (SysDeptDTO) child;
            getUserByDeptId(sysDeptUserDtos, sysUserEntity);
        }
    }


    @Override
    public SysDeptDTO get(Long id) {
        //超级管理员，部门ID为null
        if (id == null) {
            return null;
        }

        SysDeptEntity entity = baseDao.getById(id);

        return ConvertUtils.sourceToTarget(entity, SysDeptDTO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(SysDeptDTO dto) {
        SysDeptEntity entity = ConvertUtils.sourceToTarget(dto, SysDeptEntity.class);
        Long tenantId = SecurityUser.getTenantId();
        entity.setPids(getPidList(entity.getPid(), tenantId));
        entity.setStatus(0);
        entity.setSort(getSort(entity.getPid(), tenantId));
        entity.setTenantId(tenantId);
        insert(entity);
    }

    private Integer getSort(Long pid, Long tenantId) {
        List<SysDeptEntity> sysDeptEntities = baseDao.selectList(new LambdaQueryWrapper<SysDeptEntity>()
                .eq(SysDeptEntity::getPid, pid)
                .eq(SysDeptEntity::getTenantId, tenantId));
        if (sysDeptEntities.size() == 0) {
            return 0;
        }
        return sysDeptEntities.stream().map(SysDeptEntity::getSort).max(Integer::compare).get() + 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysDeptDTO dto) {
        SysDeptEntity entity = ConvertUtils.sourceToTarget(dto, SysDeptEntity.class);

        //上级部门不能为自身
        if (entity.getId().equals(entity.getPid())) {
            throw new CustomException(ErrorCode.SUPERIOR_DEPT_ERROR);
        }

        //上级部门不能为下级部门
        List<Long> subDeptList = getSubDeptIdList(entity.getId());
        if (subDeptList.contains(entity.getPid())) {
            throw new CustomException(ErrorCode.SUPERIOR_DEPT_ERROR);
        }

        entity.setPids(getPidList(entity.getPid(), SecurityUser.getTenantId()));
        updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        //判断是否有子部门
        List<Long> subList = getSubDeptIdList(id);
        if (subList.size() > 1) {
            throw new CustomException(ErrorCode.DEPT_SUB_DELETE_ERROR);
        }

        //判断部门下面是否有用户
        int count = sysUserDao.getCountByDeptId(id);
        if (count > 0) {
            throw new CustomException(ErrorCode.DEPT_USER_DELETE_ERROR);
        }

        //删除
        baseDao.deleteById(id);
    }

    @Override
    public List<Long> getSubDeptIdList(Long id) {
        List<Long> deptIdList = baseDao.getSubDeptIdList("%" + id + "%");
        deptIdList.add(id);

        return deptIdList;
    }

    /**
     * 获取所有上级部门ID
     *
     * @param pid 上级ID
     */
    private String getPidList(Long pid, Long tenantId) {
        //顶级部门，无上级部门
        if (Constant.DEPT_ROOT.equals(pid)) {
            return Constant.DEPT_ROOT + "";
        }

        //所有部门的id、pid列表
        List<SysDeptEntity> deptList = baseDao.getIdAndPidList(tenantId);

        //list转map
        Map<Long, SysDeptEntity> map = new HashMap<>(deptList.size());
        for (SysDeptEntity entity : deptList) {
            map.put(entity.getId(), entity);
        }

        //递归查询所有上级部门ID列表
        List<Long> pidList = new ArrayList<>();
        getPidTree(pid, map, pidList);

        return StringUtils.join(pidList, ",");
    }

    private void getPidTree(Long pid, Map<Long, SysDeptEntity> map, List<Long> pidList) {
        //顶级部门，无上级部门
        if (Constant.DEPT_ROOT.equals(pid)) {
            return;
        }

        //上级部门存在
        SysDeptEntity parent = map.get(pid);
        if (parent != null) {
            getPidTree(parent.getPid(), map, pidList);
        }

        pidList.add(pid);
    }
}
